#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include <linux/cdev.h>
#include <linux/device.h>
#define NAME "XYTLEDDEV"
#define CCM_CCGR1_BASE				(0X020C406C)	
#define SW_MUX_GPIO1_IO04_BASE		(0x20e006c)
#define SW_PAD_GPIO1_IO04_BASE		(0x20e02f8)
#define GPIO1_DR_BASE				(0X0209C000)
#define GPIO1_GDIR_BASE				(0X0209C004)

#define LED_ON 0
#define LED_OFF 1
#define LEDDEVCOUNT 1

//设备结构体
typedef struct  
{
    dev_t  devid;
    int major;
    int minor;
    struct cdev cdev;
    struct class *class;
    struct device *device;
}newchr_led;
newchr_led LedChr;


static void __iomem *IMX6U_CCM_CCR1;
static void __iomem *SW_MUX;
static void __iomem *SW_PAD;
static void __iomem *GPIO1_DR;
static void __iomem *GPID1_GDIR;

static void GPIO_Init(void)
{
    int val =0;
    IMX6U_CCM_CCR1 = ioremap(CCM_CCGR1_BASE, 4);
    SW_MUX = ioremap(SW_MUX_GPIO1_IO04_BASE, 4);
    SW_PAD = ioremap(SW_PAD_GPIO1_IO04_BASE, 4);
    GPIO1_DR = ioremap(GPIO1_DR_BASE, 4);
    GPID1_GDIR = ioremap(GPIO1_GDIR_BASE, 4);
    
    writel(0xffffffff, IMX6U_CCM_CCR1);
    writel(5, SW_MUX);
    writel(0x10B0, SW_PAD);

    val = readl(GPID1_GDIR);
    val |= 1 << 4;
    writel(val, GPID1_GDIR);

    val = readl(GPIO1_DR);
    val &= ~(1 << 4);
    writel(val, GPIO1_DR);
}

void LED_Staus(int staus)
{
    int val = 0;
    if (staus == LED_ON)
    {
        val = readl(GPIO1_DR);
        val &= ~(1 << 4);
        writel(val, GPIO1_DR);
        printk("LEDON\n");
    }
    else
    {
        val = readl(GPIO1_DR);
        val |= (1 << 4);
        writel(val, GPIO1_DR);
        printk("LEDOFF\n");
    }
}
static int LED_open(struct inode *inode, struct file *fs)
{
    fs->private_data = &LedChr;
    return 0;
}

static int LED_release(struct inode *inode, struct file *fs)
{
    newchr_led *chr = (newchr_led *)fs->private_data; 
    return 0;
}
static ssize_t LED_read(struct file *fs, char __user *buff, size_t count, loff_t *loff)
{
    newchr_led *chr = (newchr_led *)fs->private_data; 
    return count;
}
static ssize_t LED_write(struct file *fs, const char __user *buff, size_t count, loff_t *opps)
{
    u8 ret =0;
    char Tbuff[100] ={"      "}; 
    newchr_led *chr = (newchr_led *)fs->private_data; 
    ret = copy_from_user(Tbuff,buff,count);
    if(ret < 0)
    {
        printk("write erro\n");
        return -EIO;
    }
    else 
    {
        printk("Tbuff = %s\n",Tbuff);
        if(Tbuff[0] == '0')
        {
            LED_Staus(LED_ON);
        }
        else 
        {
            LED_Staus(LED_OFF);
        }
        return count;
    }   

}


static const struct file_operations LesFile =
{
        .owner = THIS_MODULE,
        .open = LED_open,
        .read = LED_read,
        .write = LED_write,
        .release = LED_release,
} ;


    int ret = 0;
static  int  __init LED_init(void)
{

    GPIO_Init();
    LED_Staus(LED_ON); 
    //注册字符设备
    if(LedChr.major)
    {
        printk("jing tai \n ");
        LedChr.devid = MKDEV(LedChr.major,0);
        ret =   register_chrdev_region(LedChr.devid,LEDDEVCOUNT,NAME);
        if(ret < 0)
        {
            printk("sssnewchr register fail \n");
            return -1;
        }
        else 
        {
            printk("sssMAJOR = %d     MINOR = %d \n", LedChr.major, LedChr.minor);
        }
    }
    else 
    {
        printk("dong tai \n");
       ret =  alloc_chrdev_region(&LedChr.devid,0,LEDDEVCOUNT,NAME);
        LedChr.major = MAJOR(LedChr.devid);
        LedChr.minor = MINOR(LedChr.devid);
            if(ret < 0)
            {
                printk("sssnewchr register fail \n");
                return -1;
            }
            else 
            {
                printk("sssMAJOR = %d     MINOR = %d \n", LedChr.major, LedChr.minor);
            }
    }

    
    //注册服务函数
    LedChr.cdev.owner=THIS_MODULE;
    cdev_init(&LedChr.cdev,&LesFile);
    cdev_add(&LedChr.cdev, LedChr.devid, LEDDEVCOUNT);

    //自动创建设备节点
    //创建类
   LedChr.class = class_create(THIS_MODULE,NAME);
    if(IS_ERR(LedChr.class))
    {
        printk("error 1\n");
        return PTR_ERR(LedChr.class);
    }
    //创建设备节点
    LedChr.device = device_create(LedChr.class,NULL,LedChr.devid,NULL,"XYTLEDClass");
    if(IS_ERR(LedChr.device))
    {
          printk("error 2\n");
        return PTR_ERR(LedChr.device);
    }
    return 0;
}


void  __exit LED_exit(void)
{
    LED_Staus(LED_OFF);
    unregister_chrdev_region(LedChr.devid,1);
    cdev_del(&LedChr.cdev);
    device_destroy(LedChr.class,LedChr.devid);
    //先摧毁设备 后摧毁类
    class_destroy(LedChr.class);
}

module_init(LED_init);
module_exit(LED_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xyt");